package se.vgregion.velocity.hook.regioncalendar.util;

import org.apache.abdera.i18n.iri.IRI;
import org.apache.abdera.model.Document;
import org.apache.abdera.model.Element;
import org.apache.abdera.model.Entry;
import org.apache.abdera.model.Feed;
import org.apache.abdera.protocol.Response.ResponseType;
import org.apache.abdera.protocol.client.AbderaClient;
import org.apache.abdera.protocol.client.ClientResponse;
import org.apache.abdera.protocol.client.RequestOptions;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import se.vgregion.velocity.hook.regioncalendar.model.RegionCalendarEntry;
import se.vgregion.velocity.hook.regioncalendar.model.RegionCalendarFeed;

import javax.xml.namespace.QName;
import java.text.DateFormatSymbols;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;

public class RegionCalendarUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(RegionCalendarUtil.class);

    public static int getDateNumber(Date date, Locale locale) {
        int dateNumber = -1;

        if (date != null && locale != null) {
            Calendar calendar = Calendar.getInstance(locale);
            calendar.setTime(date);
            dateNumber = calendar.get(Calendar.DATE);
        }

        return dateNumber;
    }

    public static int getMonthNumber(Date date, Locale locale) {
        int monthNumber = -1;

        if (date != null && locale != null) {
            Calendar calendar = Calendar.getInstance(locale);
            calendar.setTime(date);
            monthNumber = calendar.get(Calendar.MONTH);
        }

        return monthNumber;
    }

    public static String getShortMonthText(Date date, Locale locale) {
        String monthText = "";

        String[] shortMonths = new DateFormatSymbols().getShortMonths();
        int monthNumber = getMonthNumber(date, locale);

        if (monthNumber != -1) {
            monthText = shortMonths[monthNumber];
        }

        return monthText;
    }

    public static RegionCalendarFeed parseFeed(String url, int maxEntriesCount) {

        Feed abderaFeed = getAbderaFeed(url);
        RegionCalendarFeed regionCalendarFeed = getRegionCalendarFeed(abderaFeed);
        List<RegionCalendarEntry> regionCalendarEntries = getRegionCalendarEntries(abderaFeed, maxEntriesCount);

        regionCalendarFeed.setEntries(regionCalendarEntries);

        return regionCalendarFeed;
    }

    public static RegionCalendarFeed parseFeedAllEntries(String url) {

        Feed abderaFeed = getAbderaFeed(url);
        RegionCalendarFeed regionCalendarFeed = getRegionCalendarFeed(abderaFeed);

        int maxEntriesCount = 0;

        if (abderaFeed != null) {
            maxEntriesCount = abderaFeed.getEntries().size();
        }

        List<RegionCalendarEntry> regionCalendarEntries = getRegionCalendarEntries(abderaFeed, maxEntriesCount);

        regionCalendarFeed.setEntries(regionCalendarEntries);

        return regionCalendarFeed;
    }

    private static Feed getAbderaFeed(String url) {

        ClassLoader liferayRootClassLoader = null;
        try {
            liferayRootClassLoader = Thread.currentThread().getContextClassLoader();
            ClassLoader temporaryWebappClassLoader = RegionCalendarUtil.class.getClassLoader();
            Thread.currentThread().setContextClassLoader(temporaryWebappClassLoader);

            AbderaClient abderaClient = AbderaClientUtil.getInstance().getAbaderaClient();

            RequestOptions defaultRequestOptions = abderaClient.getDefaultRequestOptions();
            defaultRequestOptions.setNoCache(true);
            abderaClient.setConnectionTimeout(4000);
            abderaClient.setSocketTimeout(4000);

            ClientResponse clientResponse = abderaClient.get(url, defaultRequestOptions);

            Feed feed = null;

            if (clientResponse.getType() == ResponseType.SUCCESS) {
                Document<Feed> doc = clientResponse.getDocument();
                feed = doc.getRoot();
            } else {
			    LOGGER.info("FLAG - RegionCalendarUtil. getAbderaFeed. There was an error parsing the RSS feed: "
                        + clientResponse.getStatusText());
            }

            return feed;
        } finally {
            Thread.currentThread().setContextClassLoader(liferayRootClassLoader);
        }
    }

    private static RegionCalendarFeed getRegionCalendarFeed(Feed feed) {
        RegionCalendarFeed regionCalendarFeed = new RegionCalendarFeed();

        if (feed != null) {
            regionCalendarFeed.setId(feed.getId());
            regionCalendarFeed.setTitle(feed.getTitle());
            regionCalendarFeed.setUpdated(feed.getUpdated());
        }

        return regionCalendarFeed;
    }

    private static List<RegionCalendarEntry> getRegionCalendarEntries(Feed abderaFeed, int maxEntriesCount) {

        // If there is no abderaFeed. Return an empty list.
        if (abderaFeed == null) {
            return new ArrayList<RegionCalendarEntry>();
        }

        List<Entry> feedEntries = abderaFeed.getEntries();
        if (feedEntries.size() < maxEntriesCount) {
            maxEntriesCount = feedEntries.size();
        }

        ArrayList<RegionCalendarEntry> regionCalendarEntryList = new ArrayList<RegionCalendarEntry>();

        for (int i = 0; i < maxEntriesCount; i++) {
            Entry entry = feedEntries.get(i);

            RegionCalendarEntry regionCalendarEntry = getRegionCalendarEntry(entry);

            regionCalendarEntryList.add(regionCalendarEntry);
        }

        return regionCalendarEntryList;
    }

    private static RegionCalendarEntry getRegionCalendarEntry(Entry abderaEntry) {
        RegionCalendarEntry regionCalendarEntry = new RegionCalendarEntry();

        List<Element> entryElements = abderaEntry.getElements();

        IRI id = abderaEntry.getId();
        String title = abderaEntry.getTitle();

        String updatedStr = "";
        String startDateStr = "";
        String startTimeStr = "";
        String startDateFullStr = "";
        String endDateStr = "";
        String endTimeStr = "";
        String endDateFullStr = "";
        String location = "";
        String place = "";
        String type = "";
        String spaces = "";
        String authorName = "";
        String summary = "";
        String summaryHtml = "";
        String url = "";

        for (Element element : entryElements) {

            QName qname = element.getQName();
            String name = qname.getLocalPart();
            String text = element.getText();

            if (name.equals("updated")) {
                updatedStr = text;
            } else if (name.equals("startdate")) {
                startDateStr = text;
            } else if (name.equals("starttime")) {
                startTimeStr = text;
            } else if (name.equals("enddate")) {
                endDateStr = text;
            } else if (name.equals("endtime")) {
                endTimeStr = text;
            } else if (name.equals("link")) {
                String href = element.getAttributeValue("href");
                url = href;
            } else if (name.equals("location")) {
                location = text;
            } else if (name.equals("ort")) {
                place = text;
            } else if (name.equals("type")) {
                type = text;
            } else if (name.equals("spaces")) {
                spaces = text;
            } else if (name.equals("author")) {
                List<Element> authorElementList = element.getElements();
                for (Element authorElement : authorElementList) {
                    QName authorElementQname = authorElement.getQName();
                    String authorElementName = authorElementQname.getLocalPart();
                    String authorElementText = authorElement.getText();

                    if (authorElementName.equals("Name")) {
                        authorName = authorElementText;
                    }
                }
            } else if (name.equals("summary")) {

                summary = text;

                String summaryType = element.getAttributeValue("type");

                if (summaryType.equals("html")) {
                    summaryHtml = text;
                }
            }

        }

        endDateFullStr = (endTimeStr.length() > 0) ? (endDateStr + " " + endTimeStr) : endDateStr;
        startDateFullStr = (endTimeStr.length() > 0) ? (startDateStr + " " + startTimeStr) : startDateStr;

        Date updated = parseDate(updatedStr);
        Date endDate = parseDate(endDateFullStr);
        Date startDate = parseDate(startDateFullStr);

        regionCalendarEntry.setId(id);
        regionCalendarEntry.setTitle(title);
        regionCalendarEntry.setUpdated(updated);

        regionCalendarEntry.setStartDate(startDate);
        regionCalendarEntry.setEndDate(endDate);

        regionCalendarEntry.setLocation(location);
        regionCalendarEntry.setPlace(place);
        regionCalendarEntry.setType(type);
        regionCalendarEntry.setSpaces(spaces);
        regionCalendarEntry.setAuthorName(authorName);
        regionCalendarEntry.setSummary(summary);
        regionCalendarEntry.setSummaryHtml(summaryHtml);
        regionCalendarEntry.setUrl(url);

        return regionCalendarEntry;
    }

    private static Date parseDate(String dateStr) {

        int dateStrLength = dateStr.length();
        DateTimeFormatter dtf = null;

        if (dateStrLength == 10) {
            dtf = DateTimeFormat.forPattern(_DTF_PATTERN_DATE_ONLY).withZone(DateTimeZone.forID("CET"));
        } else if (dateStrLength == 19) {
            dtf = DateTimeFormat.forPattern(_DTF_PATTERN_WITH_TIME).withZone(DateTimeZone.forID("CET"));
        } else if (dateStrLength == 20) {

            dtf = ISODateTimeFormat.dateTimeNoMillis();

            // Change dateStr to cater for time zone differences
            // Could probably be done by configuring ISODateTimeFormat in some way
            dateStr = dateStr.substring(0, dateStr.length() - 1) + "+02:00";
        }

        try {
            DateTime dateTime = dtf.parseDateTime(dateStr);
            return dateTime.toDate();
        } catch (Exception e) {
            return null;
        }
    }

    private static final String _DTF_PATTERN_DATE_ONLY = "yyyy-MM-dd";
    private static final String _DTF_PATTERN_WITH_TIME = "yyyy-MM-dd HH:mm:ss";

}
